﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XbdSoft.Domain;
using XbdSoft.Contract;
using XbdSoft.Client;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Xml.Linq;
using System.Threading;

namespace XbdSoft.WPFVersion.Common
{
    #region Download DTO
    public class DownloadDTO:INotifyPropertyChanged
    {
        protected DownloadDTO() { }
        public static readonly DownloadDTO Empty = new DownloadDTO();

        public DownloadDTO(AudioResource resource)
        {
            Resource = resource;
            ID = resource.ID; 
            Initialize();
        }

        protected void Initialize()
        {
            try
            {
                using (var service = new ServiceObject<IDownloadService>(Util.DownloadServiceAddress))
                {
                    var url = service.Object.GetDownloadUrl(ID);
                    DownloadObject = new WebClientDownload(url, Util.Configuration.SaveFilePath, Resource.Title1);
                    DownloadObject.Tag = ID;
                    DownloadObject.DownloadChanged += new EventHandler<DownloadChangedEventArgs>(DownloadObject_DownloadChanged);
                    DownloadObject.DownloadCompleted += new EventHandler<EventArgs>(DownloadObject_DownloadCompleted);
                    DownloadObject.DownloadStarted += new EventHandler<EventArgs>(DownloadObject_DownloadStarted);
                }
            }
            catch(Exception ex) 
            {
                
            }
        }

        #region Properties

        public int ID { get; private set; }

        public long Size { get { return DownloadObject.TotalLength; } }
        public long DownloadSize { get { return DownloadObject.DownloadLength; } }
        public float Speed { get { return DownloadObject.Speed; } }
        public float Progress { get { return Size == 0 ? 0 : (1.0F * DownloadObject.DownloadLength) / Size; } }
        public string FileName { get { return DownloadObject.FileName; } }

        public AudioResource Resource { get; private set; }

        public DownloadStatus Status { get { return DownloadObject.Status; } }
        
        public IDownload DownloadObject { get; private set; }

        #endregion

        #region Events

        void DownloadObject_DownloadStarted(object sender, EventArgs e)
        {
            //Store the download information file.
            SaveIntoFile(this);
        }

        void DownloadObject_DownloadCompleted(object sender, EventArgs e)
        {
            // Delete the download information file.
            RemoveInfoFile(this);
        }

        void DownloadObject_DownloadChanged(object sender, DownloadChangedEventArgs e)
        {
            OnPropertyChanged("Size");
            OnPropertyChanged("Status");
            OnPropertyChanged("Speed");
            OnPropertyChanged("Progress");
            OnPropertyChanged("DownloadSize");
            OnPropertyChanged("SizeString");
            if (e.Status == DownloadStatus.Waiting)
            {
                OnPropertyChanged("FileName");
            }
        }

        #endregion

        #region Bind Properties

        public string SizeString
        {
            get
            {
                return string.Format("{0}/{1}",GetSizeStr(DownloadSize), GetSizeStr(Size));
            }
        }

        private string GetSizeStr(long actualSize)
        { 
            var size = actualSize / 1024F;
            var suffix = "KB";
            if (size > 1024)
            {
                size = size / 1024;
                suffix = "MB";
            }
            if (size > 1024)
            {
                size = size / 1024;
                suffix = "GB";
            }
            return string.Format("{0:f2}{1}", size, suffix);
        }
        #endregion

        #region INotifyPropertyChanged Members

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Static Save,Load
        public static void SaveIntoFile(DownloadDTO downloadDTO)
        {
            try
            {
                var infoFileFullName = Util.GetDownloadInfoFullName(downloadDTO.FileName);
                using (var writer = new StreamWriter(infoFileFullName, false))
                {
                    SaveIntoFile(downloadDTO, writer);
                }
            }
            catch { }
        }


        public static void SaveIntoFile(DownloadDTO downloadDTO,StreamWriter writer)
        {
            try
            {
                writer.WriteLine(string.Format("{0}", downloadDTO.ID));
                writer.WriteLine(string.Format("{0}", downloadDTO.DownloadSize));
            }
            catch { }
        }

        public static DownloadDTO LoadFromInfoFile(string downloadFileName)
        {
            try
            {
                var infoFileFullName = Util.GetDownloadInfoFullName(downloadFileName);
                using (var reader = new StreamReader(infoFileFullName))
                {
                    var idStr = reader.ReadLine();
                    var id = Convert.ToInt64(idStr);
                    var downloadLengthStr = reader.ReadLine();
                    var downloadLength = 0L;
                    long.TryParse(downloadLengthStr, out downloadLength);

                    var resource = default(AudioResource);
                    using (var downloadService = new ServiceObject<IDownloadService>(Util.DownloadServiceAddress))
                    {
                        resource = downloadService.Object.GetAudioResource(id);
                    }
                    if (resource != null)
                    {
                        var downloadDTO = new DownloadDTO(resource);
                        downloadDTO.DownloadObject.DownloadLength = downloadLength;
                        return downloadDTO;
                        //downloadDTO.DownloadObject.DownloadLength
                    }
                    //var downloadUrl = reader.ReadLine();
                }
            }
            catch { }
            return null;
        }

        public static void RemoveInfoFile(DownloadDTO downloadDTO)
        {
            try
            {
                var infoFileFullName = Util.GetDownloadInfoFullName(downloadDTO.FileName);
                if (File.Exists(infoFileFullName))
                    File.Delete(infoFileFullName);
            }
            catch { }
        }


        #endregion

        #region Helper Methods

        private long GetDownloadedLength(string downloadFileName)
        {
            long length = 0;
            string downloadFileFullName = Util.GetDownloadFileFullName(downloadFileName);
            if (File.Exists(downloadFileFullName))
            {
                using (var stream = File.Open(downloadFileFullName, FileMode.Open, FileAccess.Read))
                {
                    length = stream.Length;
                }
            }
            return length;
        }

        #endregion

        #region Remove Pause
        public void Remove(bool removeFile=true)
        {
            try
            {
                DownloadObject.Close();
                if (removeFile)
                {
                    Thread.Sleep(500);
                    var downloadFile = Util.GetDownloadFileFullName(FileName);
                    if (File.Exists(downloadFile))
                        File.Delete(downloadFile);
                    RemoveInfoFile(this);
                }
                DownloadObject = null;
            }
            catch { }
        }

        public void Pause()
        {
            try
            {
                DownloadObject.Close(); 
            }
            catch { }
        }
        #endregion
    }
    #endregion

    #region Download Status

    [Flags]
    public enum DownloadStatus
    {
        None=1,

        Downloading = 2,

        Waiting=4,

        Paused=8,

        Completed=16,

        All = 31
    }
    #endregion
     
}
